package club.kynb.mall.application.service;

import club.kynb.mall.application.config.BusinessConfig;
import club.kynb.mall.application.constant.MallResultCode;
import club.kynb.mall.application.constant.ProductOrderTypeEnum;
import club.kynb.mall.application.model.model.query.CategoryProductListQuery;
import club.kynb.mall.application.model.model.query.ProductQuery;
import club.kynb.mall.application.model.model.vo.CategoryProductListVO;
import club.kynb.mall.application.model.model.vo.ProductDetailResultVO;
import club.kynb.mall.product.api.IProductCategoryService;
import club.kynb.mall.product.api.IProductInfoService;
import club.kynb.mall.product.dto.ProductByParamDTO;
import club.kynb.mall.product.dto.ProductCategoryDTO;
import club.kynb.mall.product.dto.ProductCategoryFullDTO;
import club.kynb.mall.product.dto.ProductSpuDetailDTO;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.pizza.common.web.exception.Errors;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author kynb_club@163.com
 * @date: 2021/6/24
 */
@Slf4j
@Service
@AllArgsConstructor
public class ProductApplicationService {

    final IProductCategoryService productCategoryService;
    final IProductInfoService productInfoService;

    final BusinessConfig businessConfig;


    public List<ProductCategoryDTO> listCategoryTop(){
        return productCategoryService.listByParent(NumberUtils.LONG_ZERO);
    }

    public List<ProductCategoryFullDTO> listCategoryFull(){
        return productCategoryService.listFull();
    }

    public List<ProductSpuDetailDTO> search(ProductQuery pageQuery) {
        return listOnSaleByKeywordAndOrderType(pageQuery.getKeyword(),pageQuery.getOrderType(),businessConfig.getSearchMaxNum());
    }

    public CategoryProductListVO productListByCategory(CategoryProductListQuery query){
        CategoryProductListVO result = new CategoryProductListVO();
        List<ProductSpuDetailDTO> productSpuDTOS = listOnSaleByCateAndTag(query.getCategoryId());
        result.setSpuList(productSpuDTOS);
        return result;
    }

    public ProductDetailResultVO detailById(Long id) {
        ProductDetailResultVO result = new ProductDetailResultVO();
        ProductSpuDetailDTO detailDTO = productInfoService.detailOnSaleById(id)
                .orElseThrow(() -> Errors.BIZ.exception(MallResultCode.CODE_12001));
        result.setSpu(detailDTO);
        result.setRecommendList(listRelated(detailDTO));
        result.setRelatedList(listRelated(detailDTO));
        return result;
    }

    private List<ProductSpuDetailDTO> listRelated(ProductSpuDetailDTO detailDTO){
        String keyword = StrUtil.isEmpty(detailDTO.getSpuKeywords()) ? detailDTO.getSpuName() : StrUtil.split(detailDTO.getSpuKeywords(),StrUtil.C_COMMA).get(0);
        return listOnSaleByCateAndKeyword(null,keyword,businessConfig.getDetailRelatedNum());
    }

    private List<ProductSpuDetailDTO> listOnSaleByCateAndKeyword(Long categoryId,String keyword,Integer limit){
        return list(categoryId,keyword,null,limit);
    }

    private List<ProductSpuDetailDTO> listOnSaleByCateAndTag(Long categoryId){
        return list(categoryId,null,null,null);
    }

    private List<ProductSpuDetailDTO> listOnSaleByKeywordAndOrderType(String keyword,Integer orderType,Integer limit){
        return list(null,keyword, orderType,limit);
    }


    private List<ProductSpuDetailDTO> list(Long categoryId,String keyword, Integer orderType, Integer limit){
        ProductByParamDTO dto = new ProductByParamDTO()
                .setCateId(categoryId)
                .setKeyword(keyword);

        List<ProductSpuDetailDTO> productSpuDTOS = productInfoService.listOnSaleByParam(dto);
        Optional<ProductOrderTypeEnum> optional = ProductOrderTypeEnum.get(orderType);
        if(optional.isPresent()){
            ProductOrderTypeEnum typeEnum = optional.get();
            switch (typeEnum){
                case SALES_DESC:
                    productSpuDTOS = productSpuDTOS.stream().sorted(Comparator.comparing(ProductSpuDetailDTO::getSpuSaleNum).reversed()).collect(Collectors.toList());
                    break;
                case PRICE_ASC:
                    productSpuDTOS = productSpuDTOS.stream().sorted((spu1,spu2)-> CompareUtil.compare(spu1.getSpuPrice(),spu2.getSpuPrice(),true)).collect(Collectors.toList());
                    break;
                case PRICE_DESC:
                    productSpuDTOS = productSpuDTOS.stream().sorted((spu1,spu2)-> CompareUtil.compare(spu2.getSpuPrice(),spu1.getSpuPrice(),true)).collect(Collectors.toList());
                default:
                    break;
            }
        }
        return limit != null && productSpuDTOS.size() > limit ? productSpuDTOS.subList(0,limit) : productSpuDTOS;
    }

}
